/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Applications;

import OLDSTUFF.DataSetPackage.DataSet;
import OLDSTUFF.DataSetPackage.DataSetStorage;
import OLDSTUFF.DataSetPackage.ProductView;
import OLDSTUFF.DataSetPackage.SimpleView;
import OLDSTUFF.DataSetPackage.View;
import Estimator.EmpSuffix;
import Estimator.OLDSTUFF_EstimatorExp;
import Estimator.IndependentProductEst;
import Estimator.LaPlaceSuffix;
import Estimator.SimSuffixEstimatorExp;
import OLDSTUFF.HierarchyPackage.Hierarchy;
import OLDSTUFF.HierarchyPackage.ProductHierarchy.ProductHierarchy;
import OLDSTUFF.HierarchyPackage.AffixHierarchies.SuffixHierarchy;
import OptionsManager.DiscountOptions;
import OptionsManager.TrainOptions;
import OrderedCoverPackage.BaseHPM;
import OrderedCoverPackage.NSuffixOCEstimator;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.osdtsystem.utils.MemoryStorage;
import org.osdtsystem.utils.Storage;

/**
 *
 * @author Martin Haulrich
 */
public class Main {

    static String newline = System.getProperty("line.separator");

    /** Constructor */
    public Main() {
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {


        if (true) {

            TrainOptions options = new TrainOptions(args[0]);
            DiscountOptions discountOptions = new DiscountOptions();
            options.setIntOption("mincount", 5);
            options.setIntOption("rounds", 2);
            System.err.println(options);


            Storage storage = new MemoryStorage();
            String fn = args[1];
            DataSet ds = new DataSetStorage(storage);

            BufferedReader input = new BufferedReader(new FileReader(fn));

            // Just a counter to control how much data is readb
            int rl = 0;

            // List of words. Used to create empirical estimator
            List<String> wl = new ArrayList<String>();

            int maxread = Integer.MAX_VALUE;//Integer.parseInt(args[1]);

            int lc = 0;
            String line;
            System.err.println("Reading data...");

            List<List<String>> ngrams = new ArrayList<List<String>>();
            while (((line = input.readLine()) != null) && rl < maxread) {
                rl++;
                line = "<s> " + line + " </s>";
                String[] tokens = line.split(" ");

                for (int i = 0; i < tokens.length - 1; i++) {
                    List<String> ng = new ArrayList<String>(2);
                    ng.add("^" + tokens[i]);
                    ng.add("^" + tokens[i + 1]);
                    ngrams.add(ng);
                    ds.add(ng);
                }

//                 for (int i = 0; i < tokens.length - 2; i++) {
//                    List<String> ng = new ArrayList<String>(2);
//                    ng.add("^" + tokens[i]);
//                    ng.add("^" + tokens[i + 1]);
//                    ng.add("^" + tokens[i + 2]);
//                    ngrams.add(ng);
//                    ds.add(ng);
//                }
                for (String t : tokens) {
                    // Add prefix to word
                    String w = "^" + t;
                    wl.add(w);
                }

                lc++;
            }
            input.close();

            System.err.println("Lines read: " + lc);
            System.err.println("words read: " + wl.size());
            System.err.println("");

            System.err.println("Creating prior...");
            EmpSuffix es = new EmpSuffix(wl);

            EmpSuffix ls = new LaPlaceSuffix(es);
            // Create estimator to handle expression
            OLDSTUFF_EstimatorExp ees = new SimSuffixEstimatorExp(es, 100);
            OLDSTUFF_EstimatorExp els = new SimSuffixEstimatorExp(ls, 100);

            // Array of estimators used in product-estimator
            //EstimatorExp[] ee = {se, se};
            OLDSTUFF_EstimatorExp[] ee = {els, ees};
            //    EstimatorExp[] ee = {els, els, ees};

            // Create product-estimator
            IndependentProductEst ie = new IndependentProductEst(ee);

            OLDSTUFF_EstimatorExp pe = ie;

            System.err.println("Creating product dataset");
            // Make empty dataset

            System.err.println("DatasetSize: " + ds.size());

            // Create suffix-hiearchy
            SuffixHierarchy sufhier = new SuffixHierarchy();

            // Data for hierarchy is at index 0.

            SimpleView sufdv1 = new SimpleView(0, ds);
            SimpleView sufdv2 = new SimpleView(1, ds);
            //  SimpleView sufdv3 = new SimpleView(2, ds);

            // Create productView
            View[] views = {sufdv1, sufdv2};
            //View[] views = {sufdv1, sufdv2, sufdv3};
            ProductView pv = new ProductView(ds, views);

            Hierarchy[] hiers = {sufhier, sufhier};

            // And now we make the suf x suf producthierarchy
            ProductHierarchy phier = new ProductHierarchy(hiers);


            // Create OC on the base of the hierarchy, the estimator and a minimun count
            System.err.println("Creating cover...");
            // BaseHPM(hierarchy, prior, mincount, searchBreadth)
            BaseHPM oc = new BaseHPM(phier, pe, discountOptions);
            if (true) {
                System.err.println("Training cover...\n");

                long a = System.currentTimeMillis();
                oc.train(ds.getIDs(), pv, options);
                long b = System.currentTimeMillis();
                long t = b - a;

                System.err.println("Training time: " + t);

                oc.toDot2(args[2] + ".dot", false);


                System.err.println("CoverSize: " + oc.OCsize());
                System.err.println("BumpPost: " + oc.getBumpPostMDL(pv));

                NSuffixOCEstimator oce = new NSuffixOCEstimator(oc, phier, ie);

                oce.save(args[2]);
                PrintWriter out = new PrintWriter(new FileWriter(args[2] + ".log"));
                out.println("Data points: " + oc.dataSize());
                out.println("Train options: " + options);
                out.println("");
                out.println("Training time:" + t + "ms");
                out.println("Cover size: " + oc.OCsize());
                out.println("Score: " + oc.getBumpPostMDL(pv));
                out.close();
            }
        }

    }
}